Class("UIControl", 
{
    // -------- Fields
    has:
    {
        Properties: {is: "ro", init: null},
        Animations: {is: "ro", init: null},
        EventHandlers: {is: "ro", init: null},
        
        node: {is: "ro", init: null},
        control: {is: "ro", init: null}
		
		// Dragable
		//draggable: {is:"ro", init:false}
    },

    // -------- Constructor
    before:
    {
        initialize: function(id, props)
        {
            // init fields
        	this.Properties = {};
        	this.Animations = {};
            this.EventHandlers = {};

            // init node
        	this.node = this.initNode();
            
            // init props
            this.initProperties(id, props);

            // init events
            this.initEvent();

            // add to group wrapper
            this.control = new Kinetic.Group();
            this.control.add(this.node);
			
			if(props.draggable == true)
				this.control.setDraggable("true");
        }
    },

    // -------- Methods
    methods:
    {
        // virtual initalizers
        initNode: function() 
        {
        	return new Kinetic.Node()
        },

        initProperties: function(id, props)
        {
            // add props
            this.addProperty("ID",                  this.node.getId,                 this.node.setId,                   id);
            this.addProperty("Position",            this.node.getAbsolutePosition,   this.node.setAbsolutePosition,     {x: 0, y: 0});

            this.addProperty("Size",                this.node.getSize,               this.node.setSize);
            this.addProperty("RelativePosition",    this.node.getPosition,           this.node.setPosition);
            this.addProperty("Scale",               this.node.getScale,              this.node.setScale);
            this.addProperty("Rotation",            this.node.getRotation,           this.node.getRotation);
            this.addProperty("Centroid",            this.node.getOffset,             this.node.setOffset);
            this.addProperty("Opacity",             this.node.getOpacity,            this.node.setOpacity);
            this.addProperty("ZIndex",              this.node.getZIndex,             this.node.setZIndex);
        },

        initEvent: function()
        {
            var that = this;

            // ---- click
            this.node.on("click", function(evt)
            {               
                // inner handler
                if(that["onClick"] !== undefined)
                    that["onClick"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["click"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- double click
            this.node.on("dblclick", function(evt)
            {
                // inner handler
                if(typeof that["onDoubleClick"] != "undefined")
                    that["onDoubleClick"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["dblclick"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- dragstart
            this.node.on("dragstart", function(evt)
            {
                // inner handler
                if(typeof that["onDragStart"] != "undefined")
                    that["onDragStart"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["dragstart"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- dragsmove
            this.node.on("dragsmove", function(evt)
            {
                // inner handler
                if(typeof that["onDragMove"] != "undefined")
                    that["onDragMove"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["dragsmove"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- dragsend
            this.node.on("dragsend", function(evt)
            {
                // inner handler
                if(typeof that["onDragEnd"] != "undefined")
                    that["onDragEnd"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["dragsend"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });
            
            // ---- mouseover
            this.node.on("mouseover", function(evt)
            {
                // inner handler
                if(typeof that["onMouseOver"] != "undefined")
                    that["onMouseOver"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["mouseover"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });
            
            // ---- mouseout
            this.node.on("mouseout", function(evt)
            {
                // inner handler
                if(typeof that["onMouseOut"] != "undefined")
                    that["onMouseOut"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["mouseout"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- mouseenter
            this.node.on("mouseenter", function(evt)
            {
                // inner handler
                if(typeof that["onMouseEnter"] != "undefined")
                    that["onMouseEnter"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["mouseenter"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- mouseleave
            this.node.on("mouseleave", function(evt)
            {
                // inner handler
                if(typeof that["onMouseLeave"] != "undefined")
                    that["onMouseLeave"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["mouseleave"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- mousemove
            this.node.on("mousemove", function(evt)
            {
                // inner handler
                if(typeof that["onMouseMove"] != "undefined")
                    that["onMouseMove"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["mousemove"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- mousedown
            this.node.on("mousedown", function(evt)
            {
                // inner handler
                if(typeof that["onMouseDown"] != "undefined")
                    that["onMouseDown"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["mousedown"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- mouseup
            this.node.on("mouseup", function(evt)
            {
                // inner handler
                if(typeof that["onMouseUp"] != "undefined")
                    that["onMouseUp"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["mouseup"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- tap
            this.node.on("tap", function(evt)
            {
                // inner handler
                if(typeof that["onTap"] != "undefined")
                    that["onTap"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["tap"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- dbltap
            this.node.on("dbltap", function(evt)
            {
                // inner handler
                if(typeof that["onDoubleTap"] != "undefined")
                    that["onDoubleTap"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["dbltap"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- touchstart
            this.node.on("touchstart", function(evt)
            {
                // inner handler
                if(typeof that["onTouchStart"] != "undefined")
                    that["onTouchStart"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["touchstart"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- touchmove
            this.node.on("touchmove", function(evt)
            {
                // inner handler
                if(typeof that["onTouchMove"] != "undefined")
                    that["onTouchMove"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["touchmove"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });

            // ---- touchend
            this.node.on("touchend", function(evt)
            {
                // inner handler
                if(typeof that["onTouchEnd"] != "undefined")
                    that["onTouchEnd"](evt);
                  
                // user handler
                var handlers = that.EventHandlers["touchend"];
                if(handlers !== undefined)
                {
                    // activate all handlers
                    for(var i = 0; i < handlers.length; i++)
                        handlers[i].handler(that, evt);
                }
            });
        },

        // users shouldn't use these function directly
        addProperty: function(name, getter, setter, value)
        {
            if(typeof this.Properties[name] == "undefined")
            {
                this.Properties[name] = {get: getter, set: setter};
            
                if(typeof value != "undefined")
                    this.Properties[name].set.call(this.node, value);
            }
        },

        removeProperty: function(name)
        {
            if(typeof this.Properties[name] != "undefined")
                delete this.Properties[name];
        },

        // "real" public function for users to use
        GetControl: function()
        {
            // return the group that currently
            // outside the control
            return this.control;
        },

		GetNode: function()
		{
			return this.node;
		},
		
        GetProperty: function(name)
        {
            if(typeof this.Properties[name] != "undefined")
                return this.Properties[name].get.call(this.node);
        },

        SetProperty: function(name, value)
        {
            if(typeof this.Properties[name] != "undefined")
                this.Properties[name].set.call(this.node, value);
        },

        GetProperties: function()
        {
            var props = {};
            for(var key in this.Properties)
                props[key] = this.GetProperty(key);

            return props;
        },

        AddEventHandler: function(event, id, handler)
        {
            if(this.EventHandlers[event] === undefined)
                this.EventHandlers[event] = [];

            this.EventHandlers[event].push({id: id, handler: handler});
        },

        RemoveEventHandler: function(event, id)
        {
            if(this.EventHandlers[event] === undefined)
                return;

            if(id === undefined)
                delete this.EventHandlers[event];

            for(var i = 0; i < this.EventHandlers[event].length; i++)
                if(this.EventHandlers[event][i].id == id)
                    this.EventHandlers[event].splice(i, 1);
        }
    }
})